package com.qumitech.visualnovel.service.novel;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qumitech.visualnovel.datasource.editor.BookDAOMapper;
import com.qumitech.visualnovel.model.dao.editor.BookDAO;
import com.qumitech.visualnovel.model.dto.BookQueryDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.MultimediaInfo;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.io.File;
import java.net.URLEncoder;

import com.qumitech.visualnovel.component.thirdapi.aliyun.AliYunOSSUtil;
import com.qumitech.visualnovel.component.util.EncodeUtil;
import com.qumitech.visualnovel.component.util.CommonUtil;
import com.qumitech.visualnovel.component.config.Config;
import com.qumitech.visualnovel.model.common.BaseResponse;
import com.qumitech.visualnovel.model.dao.editor.ResourceDAO;
import com.qumitech.visualnovel.datasource.editor.ResourceDAOMapper;
import com.qumitech.visualnovel.model.dto.ResourceUpdateDTO;
import com.qumitech.visualnovel.model.dto.ResourceQueryDTO;
import com.qumitech.visualnovel.model.dto.ResourceRelationOptionsDTO;


@Slf4j
@Service
public class ResourceServiceImpl implements ResourceService {
    static final String DATA_PATH = Config.getProperty("app.dataPath");

    @Autowired
    ResourceDAOMapper resourceDAOMapper;

    @Autowired
    BookDAOMapper bookDAOMapper;

    @Override
    public BaseResponse upload(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
        String mainType = multipartRequest.getParameter("mainType");
        String subType = multipartRequest.getParameter("subType");
        String decorationType = multipartRequest.getParameter("decorationType");
        String sexIfPicture = multipartRequest.getParameter("sexIfPicture");
        String relationId = multipartRequest.getParameter("relationId");
        String bookId = multipartRequest.getParameter("bookId");
        String fileName = multipartRequest.getParameter("name");
        String isBatch = multipartRequest.getParameter("isBatch");
        List<MultipartFile> fileList = multipartRequest.getFiles("fileList");

        log.info("upload: mainType={}, subType={}, decorationType={}, sexIfPicture={}, relationId={}, bookId = {}, fileName={}, isBatch={}, fileListSize={}",
            mainType, subType, decorationType, sexIfPicture, relationId, bookId, fileName, isBatch, fileList.size());

        if (mainType==null || subType==null) {
            return new BaseResponse(-1, "资源类型错误");
        }

        String resourcePath = String.format("%s/resource/%s", "system", mainType);
        File resourceDir = new File(DATA_PATH + "user/" + resourcePath);
        if (!resourceDir.exists()) {
            resourceDir.mkdirs();
        }

        Map<String, ResourceDAO> fileRecordMap = new HashMap<>();
        fileList.forEach(file -> {
            String originalName = file.getOriginalFilename();
            String prefixName = originalName.substring(0, originalName.lastIndexOf("."));

            ResourceDAO fileRecord = new ResourceDAO();
            fileRecord.setUid(0);
            fileRecord.setMaintype(mainType);
            fileRecord.setSubtype(subType);
            fileRecord.setDecorationType(decorationType);
            fileRecord.setSexIfPicture(sexIfPicture);
            fileRecord.setRelationId(relationId==null ? null : Long.valueOf(relationId));
            fileRecord.setBookId(bookId==null ? null : Long.valueOf(bookId));

            if (decorationType != null) {
                if (!prefixName.endsWith("_preview")) {
                    fileRecordMap.put(prefixName, fileRecord);
                }
            } else {
                if (Boolean.valueOf(isBatch)) {
                    fileRecordMap.put(prefixName, fileRecord);
                } else {
                    fileRecordMap.put("NotBatchFile", fileRecord);
                }
            }
        });

        for (MultipartFile file : fileList) {
            try {
                String originalName = file.getOriginalFilename();
                String prefixName = originalName.substring(0, originalName.lastIndexOf("."));
                String suffixName = originalName.substring(originalName.lastIndexOf("."));
                String newName = EncodeUtil.md5Encode(UUID.randomUUID().toString()) + suffixName;
                String recordFileName = fileName==null || fileName.length()==0 ? prefixName : fileName;

                String ossPath = String.format("user/%s/%s", resourcePath, newName);
                AliYunOSSUtil.uploadLocateFile(file, ossPath);
                // log.info("upload file to oss: originalName={}, ossPath={}", originalName, ossPath);

                String saveName = String.format("%s/%s", resourcePath, newName);
                String localPath = DATA_PATH + "user/" + saveName;
                File newFile = new File(localPath);
                file.transferTo(newFile);
                // log.info("save file to local: originalName={}, localPath={}", originalName, localPath);

                Long duraition = null;
                if (suffixName.equalsIgnoreCase(".mp3") || suffixName.equalsIgnoreCase(".wav") || suffixName.equalsIgnoreCase(".ogg")) {
                    Encoder encoder = new Encoder();
                    MultimediaInfo info = encoder.getInfo(newFile);
                    duraition = (long)Math.ceil(info.getDuration() / 1000.0);
                }

                if (decorationType != null) {
                    if (!prefixName.endsWith("_preview")) {
                        ResourceDAO fileRecord = fileRecordMap.get(prefixName);
                        fileRecord.retainAddRecord(recordFileName, saveName, duraition);
                    } else {
                        String mapKeyName = prefixName.substring(0, prefixName.lastIndexOf("_"));
                        ResourceDAO fileRecord = fileRecordMap.get(mapKeyName);
                        if (fileRecord != null) {
                            fileRecord.retainAddAttribute("preview", saveName);
                        }
                    }
                } else {
                    if (Boolean.valueOf(isBatch)) {
                        ResourceDAO fileRecord = fileRecordMap.get(prefixName);
                        fileRecord.setRecord(recordFileName, saveName, duraition);
                    } else {
                        ResourceDAO fileRecord = fileRecordMap.get("NotBatchFile");
                        fileRecord.addRecord(recordFileName, saveName, duraition);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                String originalName = file.getOriginalFilename();
                return new BaseResponse(-1, "文件上传失败: " + originalName);
            }
        }

        fileRecordMap.forEach((keyName, fileRecord) -> {
            resourceDAOMapper.insertSelective(fileRecord);
        });
        return new BaseResponse(new ArrayList<>(fileRecordMap.values()), fileRecordMap.size());
    }

    @Override
    public void download(HttpServletResponse response, String filePath) {
        try {
            String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
            response.setContentType("text/plain; charset=utf-8");
            CommonUtil.getDownload(response, DATA_PATH + "user/" + filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public BaseResponse delete(Long id) {
        ResourceDAO record = resourceDAOMapper.selectByPrimaryKey(id);
        if (record != null) {
            record.setIfDelete(true);
            resourceDAOMapper.updateByPrimaryKeySelective(record);
        }
        return new BaseResponse();
    }

    @Override
    public BaseResponse update(Long id, HttpServletRequest request) {
        ResourceDAO record = resourceDAOMapper.selectByPrimaryKey(id);
        if (record == null) {
            return new BaseResponse(-1, "资源不存在");
        }

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
        String fileName = multipartRequest.getParameter("name");
        if (fileName!=null && fileName.length()>0) {
            record.setName(fileName);
        }

        JSONArray paths = JSONArray.parseArray(record.getPath());
        JSONArray attributes = JSONArray.parseArray(record.getAttribute());

        List<MultipartFile> fileList = multipartRequest.getFiles("fileList");
        if (fileList.size()>0 && (fileList.size()!=paths.size() || fileList.size()!=attributes.size())) {
            return new BaseResponse(-1, "资源数量不一致");
        }

        for (int idx=0; idx<fileList.size(); ++idx) {
            MultipartFile file = fileList.get(idx);
            try {
                String originalName = file.getOriginalFilename();
                String prefixName = originalName.substring(0, originalName.lastIndexOf("."));
                String suffixName = originalName.substring(originalName.lastIndexOf("."));

                String filePath = paths.getString(idx);
                AliYunOSSUtil.uploadLocateFile(file, "user/" + filePath);

                File newFile = new File(DATA_PATH + "user/" + filePath);
                file.transferTo(newFile);
                log.info("update resource: idx={}, originalName={}, filePath={}", idx, originalName, filePath);

                if (fileName==null || fileName.length()==0) {
                    attributes.getJSONObject(idx).put("name", prefixName);
                    record.setName(prefixName);
                }

                if (suffixName.equalsIgnoreCase(".mp3") || suffixName.equalsIgnoreCase(".wav") || suffixName.equalsIgnoreCase(".ogg")) {
                    Encoder encoder = new Encoder();
                    MultimediaInfo info = encoder.getInfo(newFile);
                    long duraition = (long)Math.ceil(info.getDuration() / 1000.0);
                    attributes.getJSONObject(idx).put("duraition", duraition);
                }
            } catch (Exception e) {
                e.printStackTrace();
                String originalName = file.getOriginalFilename();
                return new BaseResponse(-1, "文件上传失败: " + originalName);
            }
        }

        resourceDAOMapper.updateByPrimaryKeySelective(record);
        return new BaseResponse();
    }

    @Override
    public BaseResponse updateAttrbute(Long id, ResourceUpdateDTO param) {
        ResourceDAO record = resourceDAOMapper.selectByPrimaryKey(id);
        if (record == null) {
            return new BaseResponse(-1, "资源不存在");
        }

        record.setStatus(param.getStatus());
        resourceDAOMapper.updateByPrimaryKeySelective(record);
        return new BaseResponse();
    }

    @Override
    public BaseResponse list(ResourceQueryDTO param) {
        param.setUid(0);
        int total = resourceDAOMapper.total(param);
        List<ResourceDAO> list = resourceDAOMapper.list(param);
        for (ResourceDAO item : list) {
            Long relationId = item.getRelationId();
            if (relationId==null || relationId==0) {
                List<ResourceDAO> children = resourceDAOMapper.getRelationChildren(item.getId());
                item.setRelations(String.valueOf(children.size()));
            } else {
                ResourceDAO parent = resourceDAOMapper.selectByPrimaryKey(relationId);
                if (parent != null) item.setRelations(parent.getName());
            }
        }
        return new BaseResponse(list, total);
    }

    @Override
    public BaseResponse relationOptions(ResourceRelationOptionsDTO param) {
        param.setUid(0);
        List<HashMap<Long, String>> list = resourceDAOMapper.relationOptions(param);
        return new BaseResponse(list);
    }

    @Override
    public BaseResponse relationList(Long id) {
        ResourceDAO record = resourceDAOMapper.selectByPrimaryKey(id);
        Long relationId = record.getRelationId();
        if (relationId==null || relationId==0) {
            List<ResourceDAO> list = resourceDAOMapper.getRelationChildren(id);
            return new BaseResponse(list);
        } else {
            List<ResourceDAO> list = resourceDAOMapper.getRelationParents(relationId);
            return new BaseResponse(list);
        }
    }

    @Override
    public BaseResponse bookList(BookQueryDTO param) {
        param.setOffset(0);
        param.setLimit(Integer.MAX_VALUE);
        //过滤掉之前的书籍
        param.setStartTime("2024-09-00 00:00:00");
        param.setEndTime("2054-09-00 00:00:00");
        List<BookDAO> list = bookDAOMapper.list(param);

        JSONArray result = new JSONArray();
        for (BookDAO item : list) {
            JSONObject jItem = new JSONObject();
            jItem.put("bookId", item.getId());
            jItem.put("title", item.getTitle());
            jItem.put("category", item.getCategory());
            result.add(jItem);
        }
        return new BaseResponse(result);
    }
}
